﻿using System;

namespace Test30.Engine
{
    public abstract class Move
    {
        public MoveInfo Info => _info;

        public abstract string Description { get; }

        public void BindInfo(MoveInfo info)
        {
            if (_info != null) throw new InvalidOperationException("Cannot bind info more than once.");

            _info = info ?? throw new ArgumentNullException($"info");
        }

        public bool ShouldAttempt()
        {
            return (Rng.Int(Info.Range) < Info.Chance);
        }
        public virtual bool WillUseMove(Monster monster, Entity target)
        {
            return true;
        }
        public abstract Action GetAction(Monster monster, Entity target);
        public abstract float GetExperience(Race race);

        private MoveInfo _info;
    }
    public abstract class Move<TInstanceInfo> : Move where TInstanceInfo : new()
    {
        public override bool WillUseMove(Monster monster, Entity target)
        {
            return WillUseMove(monster, target, monster.GetMoveInstance<TInstanceInfo>());
        }

        public override Action GetAction(Monster monster, Entity target)
        {
            return GetAction(monster, target, monster.GetMoveInstance<TInstanceInfo>());
        }

        protected abstract Action GetAction(Monster monster, Entity target, TInstanceInfo info);

        protected virtual bool WillUseMove(Monster monster, Entity target, TInstanceInfo info)
        {
            return true;
        }
    }
    public class MoveInfo
    {
        public int Chance;
        public int Range;
        public int Radius;
        public INoun Noun;
        public string Verb;
        public Roller Damage;
        public Element Element;
        public EffectType Effect;

        public MoveInfo(int chance, int range)
        {
            Chance = chance;
            Range = range;

            // default the info
            Radius = 1;
            Verb = Verbs.Hit;
            Element = Element.Anima;
            Effect = EffectType.Bolt;
        }

        public MoveInfo()
            : this(1, 1)
        {
        }

        public MoveInfo Clone()
        {
            MoveInfo info = new MoveInfo
            {
                Chance = Chance,
                Range = Range,
                Radius = Radius,
                Noun = Noun,
                Verb = Verb,
                Damage = Damage,
                Element = Element,
                Effect = Effect
            };

            return info;
        }
    }
}
